home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mntlib43 / mntlib / popen.c < prev    next >
C/C++ Source or Header  |  1993-11-02  |  3KB  |  126 lines

  1. /* popen(): open a file handle to a process. Works only under MiNT.
  2.  * Written by Eric R. Smith, based on the TOS version by Kai-Uwe Bloem.
  3.  */
  4.  
  5. #include    <stdio.h>
  6. #include    <stdlib.h>
  7. #include    <process.h>
  8. #include    <fcntl.h>
  9. #include    <string.h>
  10. #include    <errno.h>
  11. #include    <unistd.h>
  12. #ifdef __TURBOC__
  13. #include <sys\types.h>
  14. #else
  15. #include <sys/types.h>
  16. #endif
  17. #include <wait.h>
  18. #include <mintbind.h>
  19.  
  20. struct _pipe {
  21.     int    pid;        /* process id of child            */
  22.     FILE    *pfile;        /* created file descriptor        */
  23.     struct _pipe    *pnext;    /* next pipe in the list.        */
  24. };
  25.  
  26. static struct _pipe    *__pipes = NULL;    /* head of pipe list    */
  27.  
  28. FILE *popen(command, type)
  29. const char    *command, *type;
  30. {
  31.     struct _pipe *p;    /* the new pipe's list entry    */
  32.     short pipfd[2];        /* pipe file handles */
  33.     int savefd;        /* saved file descriptor for parent */
  34.     int kidfd;        /* file descriptor changed in child */
  35.                 /* 1 for "r", 0 for "w" */    
  36.  
  37.     char *shell;
  38.     FILE *pipefile = 0;
  39.     extern int __mint;
  40.     long r;
  41.  
  42.     if (__mint == 0) {
  43.         errno = EINVAL;
  44.         return (FILE *)0;
  45.     }
  46.  
  47.     shell = getenv("SHELL");
  48.     if (!shell)
  49.         shell = "sh";
  50.  
  51.     /* get space for the new pipe. If we can't get it then that's that */
  52.     p = (struct _pipe *) malloc(sizeof(struct _pipe));
  53.     if (p == NULL) return (FILE *)0;
  54.  
  55.     /* initialize the new pipe entry */
  56.     kidfd = (*type == 'r') ? 1 : 0;
  57.  
  58.     r = Fdup (kidfd);
  59.     savefd = (int) r;
  60.     /* get those close-on-exec flags right...
  61.        (well just do fork/exec would be easier :-)    -nox */
  62.  
  63.     if (r < 0 || (r = Fcntl (savefd, 1L, F_SETFD)) < 0 ||
  64.         (r = Fpipe(pipfd)) < 0) {        /* can't create pipe?? */
  65.         free(p);
  66.         errno = (int) -r;
  67.         return (FILE *)0;
  68.     }
  69.  
  70.     /* other side of the pipe should be closed in the child */
  71.     (void) Fcntl(pipfd[1 - kidfd], (long) 1, F_SETFD);
  72.     Fforce(kidfd, pipfd[kidfd]);
  73.     Fclose(pipfd[kidfd]);
  74.     p->pid = spawnlp(P_NOWAIT, shell, shell, "-c", command, (char *)0);
  75.     Fforce(kidfd, savefd);
  76.     Fclose(savefd);
  77.  
  78.     if (p->pid > 0) {    /* command ran all right */
  79.     /* note: 1-kidfd tells us which handle to use in the parent */
  80.         pipefile = fdopen(pipfd[1 - kidfd], type);
  81.     }
  82.  
  83.     if (pipefile) {
  84.         p->pfile = pipefile;
  85.         p->pnext = __pipes;
  86.         __pipes = p;
  87.     }
  88.     else {
  89.         /* carefully release all resources */
  90.         Fclose (pipfd[1 - kidfd]);
  91.         if (p->pid > 0)    /* just in case... */
  92.           waitpid (p->pid, (int *) NULL, 0);
  93.         free(p);
  94.     }
  95.     return pipefile;
  96. }
  97.  
  98. /* close a pipe created by popen().
  99.  */
  100. int pclose(fp)
  101. FILE    *fp;
  102. {
  103.     struct _pipe    *p,        /* the pipe's list element    */
  104.             **q;        /* predecessor of p in the list    */
  105.     int    status = -1;        /* return status of the command    */
  106.  
  107.     /* search the pipe list for a pipe matching the FILE descriptor    */
  108.     for (p = __pipes, q = &__pipes;  p && p->pfile != fp;
  109.          q = &p->pnext, p = p->pnext);
  110.     if (p == NULL)        /* Never had a popen() for this file...    */
  111.         return status;    /* this pclose call makes no sense !    */
  112.  
  113.     fclose(p->pfile);    /* close the connection        */
  114.  
  115. /* now wait for the command to finish */
  116.     waitpid (p->pid, &status, 0);
  117.  
  118.     /* remove the pipe from the list */
  119.     *q = p->pnext;
  120.  
  121.     /* Now free the pipe entry */
  122.     free(p);
  123.  
  124.     return status;
  125. }
  126.